package cn.cas.mango.service.samenews;

import cn.cas.mango.dto.HotListDetail;
import cn.cas.mango.util.Pair;
import cn.cas.mango.util.dbscan.DBSCAN;
import cn.cas.mango.util.dbscan.Data;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch.core.search.Hit;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

@Slf4j
public class SameNewsService {
  private final Map<String, Hit<HotListDetail>> cast = new HashMap<>();

  private final SortOrder sortOrder;
  private final String sortField;

  private final List<Hit<HotListDetail>> hits;
  public SameNewsService(List<Hit<HotListDetail>> hits, SortOrder order, String sortField) {
    this.hits = hits;
    this.sortOrder = order;
    this.sortField = sortField;
  }
  private void generateCast()  {
    for (Hit<HotListDetail> hit: hits) {
      cast.put(hit.source().getKey(), hit);
    }
  }

  private Map<String, List<String>> runDBSCAN(List<Hit<HotListDetail>> hits, double factor) {
    List<Data> rawAllData = new ArrayList<>();
    for (Hit<HotListDetail> hit1: hits) {
      rawAllData.add(wrappedData(hit1));
    }
    try {
      return new DBSCAN(rawAllData).run(factor);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return new HashMap<>();
  }

  private Data wrappedData(Hit<HotListDetail> hit) {
    assert hit.source() != null;
    String id = hit.source().getKey();
    HotListDetail news = hit.source();
    Double score = hit.score();
    Set<String> keywords = new HashSet<>();
    try {
      assert news != null;
      if (news.getV_keywords() != null) {
        Object key = news.getV_keywords();
        if (key instanceof List) {
          keywords.addAll((List) key);
        } else {
          keywords.add((String) key);
        }
      }

    } catch (Exception e) {
      e.printStackTrace();
    }

    // 如果新闻时间空缺，指定一个默认时间
    String date = "2010-02-02";
    if (news.getInsert_time() != null) {
      date = news.getInsert_time();
    }
    return new Data(id, keywords, date, score, sortOrder, sortField);
  }

  private Map<String, List<Hit<HotListDetail>>> sortBySize(Map<String, List<Hit<HotListDetail>>> map) {
    Map<String, List<Hit<HotListDetail>>> ret = new LinkedHashMap<>();
    List<Pair<String, List<Hit<HotListDetail>>>> list = new ArrayList<>();
    for (String key: map.keySet()) {
      Pair<String, List<Hit<HotListDetail>>> pair = new Pair<>(key, map.get(key));
      list.add(pair);
    }
    list.sort((a,b)->{
      Integer sizeA = a.getValue().size();
      Integer sizeB = b.getValue().size();
      return -sizeA.compareTo(sizeB);
    });
    for (Pair<String, List<Hit<HotListDetail>>> pair: list) {
      ret.put(pair.getKey(), pair.getValue());
    }
    return ret;
  }

  public Map<String, List<Hit<HotListDetail>>> getSameNewsList(double factor) {
    generateCast();
    Map<String, List<String>> map = runDBSCAN(hits, factor);
    Map<String, List<Hit<HotListDetail>>> ret = new LinkedHashMap<>();
    for (String key: map.keySet()) {
      ret.put(key, new ArrayList<>());
      for (String string: map.get(key)) {
        ret.get(key).add(cast.get(string));
      }
    }
    Map<String, List<Hit<HotListDetail>>> stringListMap = sortBySize(ret);
    return stringListMap;
  }
}
